package com.xjc.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xjc.common.BpmnValidateUtil;
import com.xjc.common.FlowableOperateEnum;
import com.xjc.common.HisCommentCmd;
import com.xjc.common.R;
import com.xjc.controller.request.CompleteTaskDTO;
import com.xjc.controller.request.ModelPageRequest;
import com.xjc.controller.request.ModelRequest;
import com.xjc.controller.request.StartProcessRequest;
import com.xjc.controller.response.ExtensionElementVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.impl.context.Context;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ModelQuery;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.service.impl.persistence.entity.HistoricIdentityLinkEntity;
import org.flowable.identitylink.service.impl.persistence.entity.HistoricIdentityLinkEntityImpl;
import org.flowable.identitylink.service.impl.persistence.entity.HistoricIdentityLinkEntityManager;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 模型管理
 * </p>
 *
 * @author xiaojincai
 * @since 2025-06-10
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/model")
@Tag(description = "模型管理", name = "模型管理")
public class ModelController {

    private final RepositoryService repositoryService;
    private final RuntimeService runtimeService;
    private final HistoryService historyService;
    private final IdentityService identityService;
    private final TaskService taskService;
    private final ManagementService managerService;

    /**
     * 新增
     */
    @PostMapping("/add")
    @Operation(summary = "新增")
    public R<String> add(@Valid @RequestBody ModelRequest request) throws XMLStreamException {
        final byte[] bytes = request.getProcessDefXml().getBytes(StandardCharsets.UTF_8);
        final BpmnModel bpmnModel = BpmnValidateUtil.convertToBpmnModel(bytes);
        if (BpmnValidateUtil.validModel(bpmnModel)) {
            return R.fail("模型定义xml格式错误");
        }

        //查询当前模型定义key是否存在
        final List<Model> models = repositoryService.createModelQuery().modelKey(bpmnModel.getMainProcess().getId()).list();
        if (!CollectionUtils.isEmpty(models)) {
            return R.fail("模型标识已存在");
        }

        final Model model = repositoryService.newModel();
        model.setKey(bpmnModel.getMainProcess().getId());
        model.setName(request.getName());
        model.setCategory(request.getCategory());
        model.setMetaInfo(request.metadata(1, bpmnModel.getMainProcess().getId()));

        repositoryService.saveModel(model);

        // 保存模型文件到act_ge_bytearray表
        repositoryService.addModelEditorSource(model.getId(), bytes);

        return R.ok();
    }

    /**
     * 更新
     */
    @PostMapping("/update")
    @Operation(summary = "更新")
    public R<String> update(@Valid @RequestBody ModelRequest request) throws XMLStreamException {
        final byte[] bytes = request.getProcessDefXml().getBytes(StandardCharsets.UTF_8);
        final BpmnModel bpmnModel = BpmnValidateUtil.convertToBpmnModel(bytes);
        if (BpmnValidateUtil.validModel(bpmnModel)) {
            return R.fail("模型定义xml格式错误");
        }

        //查询当前模型定义key是否存在
        Model model = repositoryService.getModel(request.getModelId());
        if (model == null) {
            model = repositoryService.newModel();
        }

        model.setKey(bpmnModel.getMainProcess().getId());
        model.setName(request.getName());
        model.setCategory(request.getCategory());
        model.setMetaInfo(request.metadata(model.getVersion() + 1, bpmnModel.getMainProcess().getId()));
        model.setDeploymentId(null);

        repositoryService.saveModel(model);

        // 保存模型文件到act_ge_bytearray表
        repositoryService.addModelEditorSource(model.getId(), bytes);

        return R.ok();
    }

    /**
     * 删除
     */
    @DeleteMapping("/delete/{id}")
    @Operation(summary = "删除")
    public R<String> delete(@PathVariable String id) {
        repositoryService.deleteModel(id);
        return R.ok();
    }

    /**
     * 分页
     */
    @GetMapping("/page")
    @Operation(summary = "分页")
    public R<IPage<Model>> page(@Valid ModelPageRequest pageDTO) {
        final ModelQuery query = repositoryService.createModelQuery();
        pageDTO.fillQuery(query);

        final Page<Model> page = new Page<>(pageDTO.getCurrent(), pageDTO.getSize(), query.count());
        final List<Model> list = query.orderByCreateTime().desc().listPage(pageDTO.getNum(), pageDTO.getSize());
        page.setRecords(list);
        return R.ok(page);
    }

    /**
     * 详情
     */
    @GetMapping("/detail/{modelId}")
    @Operation(summary = "详情")
    public R<Model> detail(@PathVariable String modelId) {
        return R.ok(repositoryService.getModel(modelId));
    }

    /**
     * 获取流程定义文件
     */
    @GetMapping("/getProcessDefFile/{modelId}")
    @Operation(summary = "获取流程定义文件")
    public void getProcessDefFile(@PathVariable String modelId, HttpServletResponse response) throws Exception {
        byte[] modelData = repositoryService.getModelEditorSource(modelId);

        final BpmnModel bpmnModel = BpmnValidateUtil.convertToBpmnModel(modelData);
        byte[] xmlBytes = (new BpmnXMLConverter()).convertToXML(bpmnModel, "UTF-8");
        final ByteArrayInputStream in = new ByteArrayInputStream(xmlBytes);
        IoUtil.copy(in, response.getOutputStream());
        final String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8));
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.flushBuffer();
    }

    /**
     * 部署
     */
    @PostMapping("/deploy/{modelId}")
    @Operation(summary = "部署")
    public R<String> deploy(@PathVariable String modelId) throws Exception {
        final Model model = repositoryService.getModel(modelId);
        final byte[] modelData = repositoryService.getModelEditorSource(modelId);
        final BpmnModel bpmnModel = BpmnValidateUtil.convertToBpmnModel(modelData);
        repositoryService.createDeployment()
                .name(model.getName())
                .key(model.getKey())
                .tenantId(model.getTenantId())
                .category(model.getCategory())
                .addBpmnModel(bpmnModel.getMainProcess().getId() + ".bpmn20.xml", bpmnModel)
                .deploy();
        return R.ok("流程已部署");
    }

    /**
     * 获取部署列表
     */
    @GetMapping("/getDeployList")
    @Operation(summary = "获取部署列表")
    public R<List<JSONObject>> getDeployList() {
        final List<Deployment> list = repositoryService.createDeploymentQuery().list();
        final List<JSONObject> jsonObjects = new ArrayList<>();
        list.forEach(deployment -> {
            final JSONObject jsonObject = new JSONObject();
            jsonObject.set("id", deployment.getId());
            jsonObject.set("key", deployment.getKey());
            jsonObject.set("name", deployment.getName());
            jsonObject.set("category", deployment.getCategory());
            jsonObject.set("deployTime", deployment.getDeploymentTime());
            jsonObject.set("tenantId", deployment.getTenantId());
            jsonObject.set("parentDeploymentId", deployment.getParentDeploymentId());
            jsonObjects.add(jsonObject);
        });
        return R.ok(jsonObjects);
    }

    /**
     * 启动流程
     */
    @PostMapping("/startProcess")
    @Operation(summary = "启动流程")
    public R<String> startProcess(@Valid @RequestBody StartProcessRequest request) {
        //设置启动用户
        identityService.setAuthenticatedUserId("张三");

        final ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(request.getProcessDefKey(), request.getBusinessKey(), request.getVariables());
        return R.ok(processInstance.getId());
    }

    /**
     * 获取流程实例列表
     */
    @GetMapping("/getProcessInstanceList")
    @Operation(summary = "获取流程实例列表")
    public R<List<JSONObject>> getProcessInstanceList() {
        final List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
        final List<JSONObject> jsonObjects = new ArrayList<>();
        list.forEach(processInstance -> {
            final JSONObject jsonObject = new JSONObject();
            jsonObject.set("id", processInstance.getId());
            jsonObject.set("processDefinitionId", processInstance.getProcessDefinitionId());
            jsonObject.set("businessKey", processInstance.getBusinessKey());
            jsonObject.set("activityId", processInstance.getActivityId());
            jsonObject.set("isEnded", processInstance.isEnded());
            jsonObject.set("isSuspended", processInstance.isSuspended());
            jsonObject.set("startUserId", processInstance.getStartUserId());
            jsonObject.set("startTime", processInstance.getStartTime());
            jsonObject.set("rootProcessInstanceId", processInstance.getRootProcessInstanceId());
            jsonObjects.add(jsonObject);
        });
        return R.ok(jsonObjects);
    }

    /**
     * 获取自己的待办列表
     */
    @GetMapping("/getMyTaskList/{user}")
    @Operation(summary = "获取自己的待办列表")
    public R<List<JSONObject>> getMyTaskList(@PathVariable String user) {
        //获取当前用户的待办列表
        final List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned(user).list();
        final List<JSONObject> jsonObjects = new ArrayList<>();
        list.forEach(task -> {
            final TaskEntityImpl taskEntity = (TaskEntityImpl) task;
            final JSONObject jsonObject = new JSONObject();
            jsonObject.set("id", task.getId());
            jsonObject.set("name", task.getName());
            jsonObject.set("category", task.getCategory());
            jsonObject.set("assignee", task.getAssignee());
            jsonObject.set("createTime", task.getCreateTime());
            jsonObject.set("processInstanceId", task.getProcessInstanceId());
            jsonObject.set("executionId", task.getExecutionId());
            jsonObject.set("taskDefinitionKey", task.getTaskDefinitionKey());
            jsonObject.set("processDefinitionId", task.getProcessDefinitionId());
            jsonObject.set("description", task.getDescription());
            jsonObject.set("owner", task.getOwner());
            jsonObject.set("priority", task.getPriority());
            jsonObject.set("dueDate", task.getDueDate());
            jsonObjects.add(jsonObject);
        });
        return R.ok(jsonObjects);
    }

    /**
     * 完成自己的待办
     */
    @PostMapping("/completeTask")
    @Operation(summary = "完成自己的待办")
    @Transactional(rollbackFor = Exception.class)
    public R<String> completeTask(@Valid @RequestBody CompleteTaskDTO param) {
        //获取当前任务
        final Task task = taskService.createTaskQuery().taskId(param.getTaskId()).singleResult();
        if (task == null) {
            return R.fail("任务不存在");
        }
        if (task.getAssignee() == null || !task.getAssignee().equals(param.getUser())) {
            return R.fail("不是你的任务");
        }

        //是否是委派任务
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            //创建子任务并完成，方便历史纪录的展示
            TaskEntity subTask = this.createSubTask(task, task.getId(), param.getUser());
            taskService.complete(subTask.getId());
            // 添加审批意见
            managerService.executeCommand(new HisCommentCmd(task.getProcessInstanceId(), param.getTaskId(), param.getUser(), FlowableOperateEnum.Complete.name(), param.getComment()));
            taskService.resolveTask(param.getTaskId(), param.getVariables());
            return R.ok("委派任务完成");
        }

        //添加本地变量
        taskService.setVariablesLocal(param.getTaskId(), param.getLocalVariables());
        //认领任务
        taskService.claim(param.getTaskId(), param.getUser());
        //完成任务
        taskService.complete(param.getTaskId(), param.getVariables());

        addSignTaskComplete(task, param);

        // 添加审批意见
        managerService.executeCommand(new HisCommentCmd(task.getProcessInstanceId(), param.getTaskId(), param.getUser(), FlowableOperateEnum.Complete.name(), param.getComment()));

        return R.ok("任务完成");
    }

    /**
     * 委派任务
     */
    @PostMapping("/resoleTask")
    @Operation(summary = "委派任务")
    @Transactional(rollbackFor = Exception.class)
    public R<String> resoleTask(@Valid @RequestBody CompleteTaskDTO param) {
        //获取当前任务
        final Task task = taskService.createTaskQuery().taskId(param.getTaskId()).singleResult();
        if (task == null) {
            return R.fail("任务不存在");
        }

        if (param.getDelegateUser() == null || param.getDelegateUser().isEmpty()) {
            return R.fail("请选择委派用户");
        }

        // 添加审批意见
        managerService.executeCommand(new HisCommentCmd(task.getProcessInstanceId(), param.getTaskId(), param.getUser(), FlowableOperateEnum.Delegate.name(), param.getComment()));
        taskService.delegateTask(param.getTaskId(), param.getDelegateUser());

        return R.ok("任务委派完成");
    }

    /**
     * 转办任务
     */
    @PostMapping("/transferTask")
    @Operation(summary = "转办任务")
    @Transactional(rollbackFor = Exception.class)
    public R<String> transferTask(@Valid @RequestBody CompleteTaskDTO param) {

        //获取当前任务
        final Task task = taskService.createTaskQuery().taskId(param.getTaskId()).singleResult();
        if (task == null) {
            return R.fail("任务不存在");
        }

        if (param.getTransferUser() == null || param.getTransferUser().isEmpty()) {
            return R.fail("请选择转办用户");
        }

        //创建转子任务并完成，以便追踪
        final TaskEntity subTask = this.createSubTask(task, task.getParentTaskId(), param.getUser());
        taskService.setVariablesLocal(subTask.getId(), param.getLocalVariables());
        taskService.complete(subTask.getId(), param.getVariables());
        //添加处理意见
        managerService.executeCommand(new HisCommentCmd(task.getProcessInstanceId(), subTask.getId(), param.getUser(), FlowableOperateEnum.Transfer.name(), param.getComment()));

        //将本任务转办
        taskService.setAssignee(task.getId(), param.getTransferUser());
        taskService.setOwner(task.getId(), param.getUser());

        return R.ok("任务转办完成");
    }

    /**
     * 加签任务
     * <p>
     * <pre>
     * 整个流程实现原理：
     * 1、把当前任务的委派人（Owner）更新为当前处理人且执行者置为空；
     * 2、给被加签人创建一个子任务；
     * 3、当子任务完成时，通过方法resolveTask(taskId)将任务状态返回给原委派人（Owner），此时任务会重新出现在原委派人的待办列表中
     * 效果如下：
     * 前加签处理: A->B 对A进行前加签任务C，则C->A->B 当子任务完成后，自动将A任务返回给原委派人
     * 后加签处理: A->B 对A进行后加签任务C，则A->C->B 当子任务完成后，自动完成A任务
     * </pre>
     * </p>
     */
    @PostMapping("/addSignTask")
    @Operation(summary = "加签任务")
    @Transactional(rollbackFor = Exception.class)
    public R<String> addSignTask(@Valid @RequestBody CompleteTaskDTO param) {
        final TaskEntityImpl task = (TaskEntityImpl) taskService.createTaskQuery().taskId(param.getTaskId()).singleResult();
        Assert.notNull(task, "当前任务不能为空");
        Assert.notEmpty(param.getSignUsers(), "加签用户不能为空");

        final String type = param.getSignType() == 1 ? FlowableOperateEnum.BeforeSign.name() : FlowableOperateEnum.AfterSign.name();

        //1 把当前任务的委派人（Owner）更新为当前处理人且执行者置为空
        task.setOwner(param.getUser());
        task.setAssignee(null);
        task.setCountEnabled(true);
        task.setScopeType(type);
        taskService.saveTask(task);

        //2 如果是候选人，需要删除运行时候选表中此用户的数据；因为认领了还没完成，还是可以看到（走到这里默认已经认领了）
        long candidateCount = taskService.createTaskQuery().taskId(task.getId()).taskCandidateUser(param.getUser()).count();
        if (candidateCount > 0) {
            syncIdentityLinkToHistory(task.getProcessInstanceId(), task.getId(), param.getUser());
            taskService.deleteCandidateUser(task.getId(), param.getUser());
        }

        //3 创建被加签人的任务列表
        param.getSignUsers().forEach(userId -> {
            if (StrUtil.isNotBlank(userId)) {
                this.createSubTask(task, task.getId(), userId);
            }
        });

        //3 添加审批意见
        managerService.executeCommand(new HisCommentCmd(task.getProcessInstanceId(), task.getId(), param.getUser(), type, param.getComment()));
        return R.ok("加签成功");
    }

    /**
     * 获取任务时间线
     */
    @GetMapping("/getTaskTimeLine/{processInstanceId}")
    @Operation(summary = "获取任务时间线")
    public R<List<JSONObject>> getTaskTimeLine(@PathVariable String processInstanceId) {
        //查询历史任务
        final List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime()
                .asc()
                .list();

        //查询历史变量
        final List<HistoricVariableInstance> variableInstances = historyService
                .createHistoricVariableInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();

        return R.ok(historicTaskInstances.stream()
                .map(item -> {
                    final JSONObject jsonObject = (JSONObject) JSONUtil.parse(item);
                    final List<JSONObject> variables = new ArrayList<>();
                    final List<JSONObject> variablesLocal = new ArrayList<>();
                    variableInstances.forEach(e -> {
                        final JSONObject json = new JSONObject();
                        json.set("name", e.getVariableName());
                        json.set("value", e.getValue());
                        if (e.getTaskId() == null) {
                            variables.add(json);
                            return;
                        }
                        if (item.getId().equals(e.getTaskId())) {
                            variablesLocal.add(json);
                        }
                    });

                    jsonObject.set("variables", variables);
                    jsonObject.set("variablesLocal", variablesLocal);
                    return jsonObject;
                }).toList());
    }

    /**
     * 根据流程实例id获取完整时间轴
     */
    @GetMapping("/getTimeLine/{processInstanceId}")
    @Operation(summary = "根据流程实例id获取完整时间轴")
    public R<List<JSONObject>> getTimeLine(@PathVariable String processInstanceId) {
        final List<JSONObject> timeLine = new ArrayList<>();
        // 获取历史节点
        final List<HistoricActivityInstance> history = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();

        // 获取运行时节点（仅未结束时）
        final List<ActivityInstance> runtime = runtimeService.createActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();

        final Map<String, String> activity = new HashMap<>();
        // 合并数据
        timeLine.addAll(history.stream()
                .map(item -> {
                    activity.put(item.getActivityId(), item.getActivityName());
                    final JSONObject jsonObject = JSONUtil.parseObj(item);
                    jsonObject.set("startTime", item.getStartTime() != null ? DateUtil.formatDate(item.getStartTime()) : "");
                    jsonObject.set("endTime", item.getEndTime() != null ? DateUtil.formatDate(item.getEndTime()) : "");
                    return jsonObject;
                }).toList());
        timeLine.addAll(runtime.stream()
                .filter(item -> !activity.containsKey(item.getActivityId()))
                .map(item -> {
                    final JSONObject jsonObject = JSONUtil.parseObj(item);
                    jsonObject.set("startTime", item.getStartTime() != null ? DateUtil.formatDate(item.getStartTime()) : "");
                    jsonObject.set("endTime", item.getEndTime() != null ? DateUtil.formatDate(item.getEndTime()) : "");
                    return jsonObject;
                }).toList());
        //当开始时间一样，则按结束时间排序
        timeLine.sort((o1, o2) ->
                !o1.getStr("transactionOrder").equals(o2.getStr("transactionOrder")) ? o1.getStr("transactionOrder").compareTo(o2.getStr("transactionOrder")) :
                        (o1.getStr("startTime").equals(o2.getStr("startTime")) ?
                                o1.getStr("endTime").compareTo(o2.getStr("endTime")) : o1.getStr("startTime").compareTo(o2.getStr("startTime"))));
        return R.ok(timeLine);
    }

    /**
     * 根据任务id获取流程定义文件的任务节点自定义变量
     */
    @GetMapping("/getTaskCustomElement/{taskId}")
    @Operation(summary = "根据任务id获取流程定义文件的任务节点自定义变量")
    public R<Map<String, List<ExtensionElementVO>>> getTaskCustomElement(@PathVariable String taskId) {
        //获取任务
        final Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            log.error("获取模型定义文件任务节点自定义变量--任务[{}]不存在", taskId);
            return null;
        }

        // 获取流程定义模型
        final BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        if (bpmnModel == null) {
            log.error("获取模型定义文件任务节点自定义变量--模型[{}]不存在", task.getProcessDefinitionId());
            return null;
        }

        //获取任务节点
        final FlowElement flowElement = bpmnModel.getProcesses().get(0).getFlowElement(task.getTaskDefinitionKey());
        if (flowElement == null) {
            log.error("获取模型定义文件任务节点自定义变量--任务[{}]节点不存在", task.getTaskDefinitionKey());
            return null;
        }
        final List<ExtensionElementVO> attributes = new ArrayList<>();
        extensionElementHandle(flowElement.getExtensionElements(), attributes);
        return R.ok(attributes.stream().collect(Collectors.groupingBy(ExtensionElementVO::getElementName)));
    }

    /**
     * 创建子任务
     *
     * @param parentTask 父级任务
     * @param assignee   子任务的执行人
     * @return 子任务
     */
    protected TaskEntity createSubTask(Task parentTask, String parentTaskId, String assignee) {
        Assert.notNull(parentTask, "父级任务不能为空");

        final TaskEntity task = (TaskEntity) taskService.newTask(UUID.randomUUID().toString().replace("-", ""));
        task.setCategory(parentTask.getCategory());
        task.setDescription(parentTask.getDescription());
        task.setTenantId(parentTask.getTenantId());
        task.setAssignee(assignee);
        task.setName(parentTask.getName());
        task.setParentTaskId(parentTaskId);
        task.setScopeType(parentTask.getScopeType());
        task.setProcessDefinitionId(parentTask.getProcessDefinitionId());
        task.setProcessInstanceId(parentTask.getProcessInstanceId());
        task.setTaskDefinitionKey(parentTask.getTaskDefinitionKey());
        task.setTaskDefinitionId(parentTask.getTaskDefinitionId());
        task.setPriority(parentTask.getPriority());
        task.setCreateTime(new Date());
        taskService.saveTask(task);
        return task;
    }

    /**
     * 任务节点与参与者（用户/组）的关系 同步至历史表
     *
     * @param taskId 任务id
     */
    public void syncIdentityLinkToHistory(String processInstanceId, String taskId, String user) {
        final List<IdentityLink> identityLinks = runtimeService.getIdentityLinksForProcessInstance(processInstanceId);
        if (identityLinks == null || identityLinks.isEmpty()) {
            return;
        }

        final CommandContext commandContext = Context.getCommandContext();
        final ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        final HistoricIdentityLinkEntityManager historicIdentityLinkEntityManager = processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkEntityManager();

        identityLinks.stream()
                .filter(item -> taskId.equals(item.getTaskId()) && user.equals(item.getUserId()))
                .forEach(item -> {
                    final HistoricIdentityLinkEntity hisIdentityLink = new HistoricIdentityLinkEntityImpl();
                    hisIdentityLink.setGroupId(item.getGroupId());
                    hisIdentityLink.setType(item.getType());
                    hisIdentityLink.setUserId(item.getUserId());
                    hisIdentityLink.setTaskId(taskId);
                    hisIdentityLink.setCreateTime(new Date());
                    hisIdentityLink.setProcessInstanceId(processInstanceId);
                    hisIdentityLink.setScopeId(item.getScopeId());
                    hisIdentityLink.setSubScopeId(item.getSubScopeId());
                    hisIdentityLink.setScopeType(item.getScopeType());
                    hisIdentityLink.setScopeDefinitionId(item.getScopeDefinitionId());
                    historicIdentityLinkEntityManager.insert(hisIdentityLink, false);
                });
    }

    /**
     * 获取流程定义文件的任务节点扩展元素信息
     *
     * @param extensionElements 扩展元素
     * @param attributes        扩展元素数据
     */
    private void extensionElementHandle(Map<String, List<ExtensionElement>> extensionElements, List<ExtensionElementVO> attributes) {
        if (extensionElements == null || extensionElements.isEmpty()) {
            return;
        }

        extensionElements.forEach((key, value) -> {
            value.forEach(element -> {
                ExtensionElementVO extensionEleVO = new ExtensionElementVO(element.getName(), element.getElementText(), null, new ArrayList<>());
                attributes.add(extensionEleVO);
                if (element.getAttributes() != null && !element.getAttributes().isEmpty()) {
                    Map<String, List<String>> attr = new HashMap<>();
                    element.getAttributes().forEach((k, v) -> {
                        attr.put(k, v.stream().map(ExtensionAttribute::getValue).toList());
                    });
                    extensionEleVO.setAttributes(attr);
                }
                if (element.getChildElements() == null || element.getChildElements().isEmpty()) {
                    return;
                }

                extensionElementHandle(element.getChildElements(), extensionEleVO.getChildElements());
            });
        });
    }

    private void addSignTaskComplete(Task task, CompleteTaskDTO param){
        if (StrUtil.isBlank(task.getParentTaskId())) {
            return;
        }

        //获取子任务
        long subTaskCount = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list()
                .stream().filter(t -> task.getParentTaskId().equals(t.getParentTaskId())).count();
        if (subTaskCount == 0) {
            final Task parentTask = taskService.createTaskQuery().taskId(task.getParentTaskId()).singleResult();
            //先将父任务返还给原委派人
            taskService.resolveTask(task.getParentTaskId());
            if (FlowableOperateEnum.AfterSign.name().equals(parentTask.getScopeType())) {
                //如果是后加签，则直接完成父任务，流程自动流转至下一个节点
                taskService.complete(task.getParentTaskId(), param.getVariables());

                if(StrUtil.isBlank(parentTask.getParentTaskId())){
                    return;
                }

                addSignTaskComplete(parentTask, param);
            }
        }
    }
}
